package com.capsulode.excel;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class CsvExporter<T> implements Closeable {
    private final List<Function<T, Serializable>> serializers = new ArrayList<>();
    private final Writer writer;
    private int line = 0;

    public CsvExporter(Writer writer) {
        this.writer = writer;
    }

    public CsvExporter<T> column(String header, Function<T, Serializable> serializer) throws IOException {
        if (line > 0) {
            throw new IllegalStateException("Header definition is already completed!");
        }
        if (serializers.size() > 0) {
            writer.write(',');
        }
        writer.append(header);
        serializers.add(serializer);
        return this;
    }

    public CsvExporter<T> writeHttpHeader(String filename,HttpServletResponse response){
        String encodedFilename;
        try {
            encodedFilename = URLEncoder.encode(filename, "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UTF-8 encoding unsupported!?");
        }
        response.setContentType("text/csv; charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename="+encodedFilename+".csv; filename*=UTF-8''"+encodedFilename+".csv");
        return this;
    }

    public CsvExporter<T> writeUTF8Bom() throws IOException {
        writer.write(new String(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}));
        return this;
    }

    public CsvExporter<T> write(T row) throws IOException {
        line++;
        writer.write('\n');

        for (int i = 0; i < serializers.size(); i++) {
            if (i > 0) {
                writer.write(',');
            }
            Serializable columnValue = serializers.get(i).apply(row);
            writer.append(columnValue == null ? "" : columnValue.toString());
        }

        if (line % 100 == 0) {
            writer.flush();
        }
        return this;
    }

    @Override
    public void close() throws IOException {
        writer.flush();
        writer.close();
    }
}
